Creating HTML User Interfaces for Server Programs by Michael Janulaitis Example 1: LoadModule acme_module modules/AcmeModule.dll SetHandler acme-handler acmeServerHost localhost acmeServerPort 28500 Listing One /* The sample code provided is for Windows only */ /* main.c */ #include #include #include #include "acmeprotocol.h" /* user entry which contains a key and a name */ typedef struct { DWORD key; char *user; char *pswd; }USER_T; /* static list that contains three users */ static USER_T users[] = { { 0xFFFFFFFF, "Manny", "manny" }, { 0xFFFFFFFF, "Moe", "moe" }, { 0xFFFFFFFF, "Jack", "jack" } }; int main(int argc, char **argv) { ACMEPROTOCOL_T command, response; BOOL bQuit = FALSE; BYTE *pbt; char input, packet[256], *pswd, *user; DWORD key, localkey = 0, *pdw; int fromlen, i, rc; FD_SET fdsErr, fdsRead, fdSet; struct sockaddr_in from, local; SOCKET s, msgsock; SYSTEMTIME ts; struct timeval t = { 1, 0}; WORD *pw; WSADATA wsadata; /* create the server */ if (WSAStartup(MAKEWORD(2,2), &wsadata)) return -1; local.sin_family = AF_INET; local.sin_port = htons(28500); local.sin_addr.s_addr = htonl(INADDR_ANY); s = socket(AF_INET, SOCK_STREAM, 0); if(INVALID_SOCKET == s) { WSACleanup(); return -1; } if (bind(s,(struct sockaddr*)&local,sizeof(local) ) == SOCKET_ERROR) bQuit = TRUE; if (listen(s,SOMAXCONN) == SOCKET_ERROR) bQuit = TRUE; FD_ZERO(&fdSet); FD_SET(s, &fdSet); while(!bQuit) { while(!kbhit()) { memcpy((void*)&fdsRead,(void*)&fdSet, sizeof(fd_set)); memcpy((void*)&fdsErr, (void*)&fdSet, sizeof(fd_set)); rc = select(0, &fdsRead, NULL, &fdsErr, &t); if (SOCKET_ERROR == rc) { bQuit = TRUE; break; } if (!rc) continue; if (FD_ISSET(s, &fdsErr)) { bQuit = TRUE; break; } if (!FD_ISSET(s, &fdsRead)) continue; fromlen = sizeof(from); msgsock = accept(s,(struct sockaddr*)&from, &fromlen); if (msgsock == INVALID_SOCKET) { bQuit = TRUE; break; } /* Get the command. Note that the data must be sent in one packet otherwise this program will fail. This program also assumes the correct data is sent. You will need to write a packet handler to deal with these issues */ rc = recv(msgsock,packet,sizeof(packet),0 ); if (SOCKET_ERROR != rc && rc && rc >= sizeof(ACMEPROTOCOL_T) + sizeof(DWORD)) { /* handle the command */ pbt = packet; pw = (WORD*)pbt; command.cmd = (WORD)ntohs(*pw); pbt += sizeof(WORD); pw = (WORD*)pbt; command.status = (WORD)ntohs(*pw); pbt += sizeof(WORD); pdw = (DWORD*)pbt; command.size = (DWORD)ntohl(*pdw); pbt += sizeof(DWORD); pdw = (DWORD*)pbt; key = (DWORD)ntohl(*pdw); pbt += sizeof(DWORD); response.cmd = command.cmd; response.status = 0; response.size = 0; switch (command.cmd) { case CMD_LOGIN: user = pbt; /* protocol handler required */ pbt += strlen(user) + 1; pswd = pbt; /* protocol handler required */ for (i = 0; i < 3; i++) { if (!strcmp(users[i].user, user)) { if (!strcmp(users[i].pswd, pswd)) { users[i].key = ++localkey; pbt = packet; pbt += sizeof(ACMEPROTOCOL_T); pdw = (DWORD*)pbt; *pdw = htonl(users[i].key); response.size = sizeof(DWORD); response.status = 1; } break; } } break; case CMD_LOGOUT: for (i = 0; i < 3; i++) { if (users[i].key == key) { users[i].key = 0xFFFFFFFF; response.status = 1; break; } } break; case CMD_GETTIME: for (i = 0; i < 3; i++) { if (users[i].key == key) { GetSystemTime(&ts); pbt = packet; pbt += sizeof(ACMEPROTOCOL_T); _snprintf(pbt, sizeof(packet) - sizeof(ACMEPROTOCOL_T), "%02d:%02d:%02d", ts.wHour, ts.wMinute, ts.wSecond); pbt[sizeof(packet) - sizeof(ACMEPROTOCOL_T) - 1] = 0; response.size = strlen(pbt) + 1; response.status = 1; break; } } break; } pbt = packet; pw = (WORD*)pbt; *pw = htons(response.cmd); pbt += sizeof(WORD); pw = (WORD*)pbt; *pw = htons(response.status); pbt += sizeof(WORD); pdw = (DWORD*)pbt; *pdw = htonl(response.size); pbt += sizeof(DWORD); send(msgsock,packet,sizeof(ACMEPROTOCOL_T) + response.size,0); } closesocket(msgsock); } input = getch(); if (input == 'q') break; } closesocket(s); WSACleanup(); return 0; } /* acmdprotocol.h */ #ifndef ACMEPROTOCOL_H #define ACMEPROTOCOL_H typedef struct { WORD cmd; WORD status; DWORD size; }ACMEPROTOCOL_T; typedef enum { CMD_LOGIN, CMD_LOGOUT, CMD_GETTIME, }CMD; #endif Listing Two static char g_host[256]; static WORD g_port = 28500; BOOL CAcmeISAPIFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer) { // Call default implementation for initialization CHttpFilter::GetFilterVersion(pVer); // Clear the flags set by base class pVer->dwFlags &= ~SF_NOTIFY_ORDER_MASK; // Set the flags we are interested in pVer->dwFlags |= SF_NOTIFY_ORDER_LOW | SF_NOTIFY_SECURE_PORT | SF_NOTIFY_NONSECURE_PORT | SF_NOTIFY_PREPROC_HEADERS; // Load description string TCHAR sz[SF_MAX_FILTER_DESC_LEN+1]; ISAPIVERIFY(::LoadString(AfxGetResourceHandle(), IDS_FILTER, sz, SF_MAX_FILTER_DESC_LEN)); _tcscpy(pVer->lpszFilterDesc, sz); DWORD port, type, size; HKEY hKey; g_host[0] = 0; // Open the registry if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("software\\acme"), 0, KEY_READ, &hKey)) return FALSE; // Get the server application host size = sizeof(g_host); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("host"), 0, &type, (BYTE*)&g_host, &size)) { RegCloseKey(hKey); return FALSE; } // Get the mas port size = sizeof(port); if (ERROR_SUCCESS != RegQueryValueEx(hKey, _T("port"), 0, &type, (BYTE*)&port, &size)) { RegCloseKey(hKey); return FALSE; } g_port = (WORD)port; // Close the registry RegCloseKey(hKey); return TRUE; } Listing Three DWORD CAcmeISAPIFilter::OnPreprocHeaders(CHttpFilterContext* pfc, PHTTP_FILTER_PREPROC_HEADERS pHeaders) { TCHAR url[256], newurl[256], *test; DWORD size = sizeof(url); if (pHeaders->GetHeader(pfc->m_pFC,_T("URL"),url,&size)) { test = _tcsstr(url, _T("/acme")); if (test) { test += _tcslen(_T("/acme")); if (test[0]) { _sntprintf(newurl, 256, _T("/Scripts/AcmeISAPI.dll%s"), test); newurl[255] = 0; } else _tcscpy(newurl, _T("/Scripts/AcmeISAPI.dll")); pHeaders->SetHeader(pfc->m_pFC, _T("URL"), newurl); } } return CHttpFilter::OnPreprocHeaders(pfc, pHeaders); } 5